import { scale } from "gl-matrix-ts/dist/mat4";
import { Matrix4 } from "../../utils/Matrix4";
import { MatrixUtil } from "../../utils/MatrixUtil";
import { Primitives } from "../../utils/Primitives";
import { TextrueUtil } from "../../utils/TextureUtil";
import { Util } from "../../utils/Util";
import { WebGLUtil } from "../../utils/WebGLUtil";
import { IProgramInfo } from "../interface/IDefine";
import { Render } from "../Render";
import { WebglTemplateBase } from "./WebglTemplateBase";

/*
 * @Author: Snow
 * @Date: 2021-10-11 15:08:49
 * @Description:  文本纹理
 */
export class TemplateText3D extends WebglTemplateBase {

    private textProgramInfo: IProgramInfo;

    protected override initUITools(): void {
        super.initUITools();
    }

    protected override initProgram(): void {
        this.vsSource = `
            attribute vec4 a_position;
            attribute vec4 a_color;
            
            uniform mat4 u_matrix;
            
            varying vec4 v_color;
            
            void main() {
                // Multiply the position by the matrix.
                gl_Position = u_matrix * a_position;
                
                // Pass the color to the fragment shader.
                v_color = a_color;
            }
        `;

        this.fsSource = `
            precision mediump float;

            // Passed in from the vertex shader.
            varying vec4 v_color;
            
            void main() {
                gl_FragColor = v_color;
            }
        `;

        let textVsSource = `
            attribute vec4 a_position;
            
            attribute vec2 a_texcoord;

            uniform mat4 u_matrix;

            varying vec2 v_texcoord;
            
            
            void main() {
                // Multiply the position by the matrix.
                gl_Position = u_matrix * a_position;

                v_texcoord = a_texcoord;
            }
        `;

        let textFsSource = `
            precision mediump float;

            // Passed in from the vertex shader.
            uniform sampler2D u_texture;
            
            varying vec2 v_texcoord;

            void main() {
                gl_FragColor = texture2D(u_texture, v_texcoord);
                //gl_FragColor = vec4(1,0,0,1);
            }
        `;
        super.initProgram();

        this.textProgramInfo = WebGLUtil.createProgramInfo(Render.GL, textVsSource, textFsSource);
    }

    protected override initBuffers(): void {
        super.initBuffers();
        const gl = Render.GL;
        // an indexed quad

        let textCtx = document.createElement("canvas").getContext("2d");

        let makeTextCanvs = (text: string, width: number, height: number): HTMLCanvasElement => {
            textCtx.canvas.width = width;
            textCtx.canvas.height = height;
            textCtx.font = "20px monospace";
            textCtx.textAlign = "center";
            textCtx.textBaseline = "middle";
            textCtx.fillStyle = "black";
            //textCtx.fillStyle = "#F0F";
            textCtx.clearRect(0, 0, textCtx.canvas.width, textCtx.canvas.height);
            textCtx.fillText(text, width / 2, height / 2);
            return textCtx.canvas;
        }

        let fBufferInfo = Primitives.createBufferInfoFunc(Primitives.create3DFVertices)(gl);

        let textBufferInfo = Primitives.createBufferInfoFunc(Primitives.createPlaneVertices)(gl, 1, 1, 1, 1, Matrix4.rotateX(Math.PI / 2))

        // an indexed quad
        let pos = [
            -1, -1, 0,
            -1, 1, 0,
            1, 1, 0,
            1, -1, 0
        ];
        let texcoord = [
            0, 1,
            0, 0,
            1, 0,
            1, 1
        ];
        let indices = [
            0, 1, 3,
            1, 2, 3,
        ];
        let arrays = {
            position: { numComponents: 3, data: pos, },
            texcoord: { numComponents: 2, data: texcoord },
            indices: { numComponents: 3, data: indices }
        };

        let rectTextBufferInfo = WebGLUtil.createBufferInfoFromArrays(gl, arrays);

        let textCanvs = makeTextCanvs("Hello!", 100, 20);
        let textTexture = gl.createTexture();
        let textWidth = textCanvs.width;
        let textHeight = textCanvs.height;
        gl.bindTexture(gl.TEXTURE_2D, textTexture);
        //告诉WebGL不用做反预乘
        gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textCanvs);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

        // 展示结果
        textCtx.canvas.toBlob((blob) => {
            const img = new Image();
            img.src = URL.createObjectURL(blob);
            document.body.appendChild(img);
        });

        var fUniforms = {
            u_matrix: Matrix4.identity(),
        };

        var textUniforms = {
            u_matrix: Matrix4.identity(),
            u_texture: textTexture,
        };


        let cameraAngleRadians = Util.degToRad(0);
        let fieldOfViewRadians = Util.degToRad(60);
        let cameraHeight = 50;




        let objects = [];
        let numObjects = 300;
        let baseColor = Util.rand(240);
        var translation = [0, 30, 0];


        let drawScene = () => {
            let time = this.ts;
            time = time * 0.1 + 5;
            WebGLUtil.resizeCanvasToMatchDisplaySize(gl);
            // Clear the canvas AND the depth buffer.
            //gl.enable(gl.CULL_FACE);
            gl.enable(gl.DEPTH_TEST);

            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);



            // Compute the projection matrix
            let aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
            var projectionMatrix = Matrix4.perspective(fieldOfViewRadians, aspect, 1, 2000);

            // Compute the camera's matrix using look at.
            let camaraRadio = 360; // 相机半径
            let mat = Matrix4.rotateY(time * 10);
            mat = Matrix4.multiply(mat, Matrix4.translation(0, 0, camaraRadio));

            let cameraPosition = [mat[12], mat[13], mat[14]];
            let target = [0, 0, 0];
            let up = [0, 1, 0];
            let cameraMatrix = Matrix4.lookAt(cameraPosition, target, up);

            // Make a view matrix from the camera matrix.
            let viewMatrix = Matrix4.invert(cameraMatrix);

            var spread = 170;

            var textPositions = [];

            gl.disable(gl.BLEND);
            gl.depthMask(true);

            for (let i = -1; i <= 1; i++) {
                for (let j = -2; j <= 2; j++) {
                    let fWorldMatrix = Matrix4.translation(translation[0] + j * spread, translation[1] + i * spread, translation[2]);
                    fWorldMatrix = Matrix4.multiply(fWorldMatrix, Matrix4.rotateX(time * 5));
                    fWorldMatrix = Matrix4.multiply(fWorldMatrix, Matrix4.translation(-50, -75, 0));

                    let fviewProjectionMatrix = Matrix4.multiply(projectionMatrix, viewMatrix);
                    fviewProjectionMatrix = Matrix4.multiply(fviewProjectionMatrix, fWorldMatrix);

                    fUniforms.u_matrix = fviewProjectionMatrix;

                    textPositions.push(fWorldMatrix[12], fWorldMatrix[13], fWorldMatrix[14]);

                    gl.useProgram(this.programInfo.program);

                    WebGLUtil.setBuffersAndAttributes(gl, this.programInfo.attribSetters, fBufferInfo);
                    WebGLUtil.setUniforms(this.programInfo.uniformSetters, fUniforms);
                    WebGLUtil.drawBufferInfo(gl, fBufferInfo);

                }
            }

            gl.enable(gl.BLEND);
            //gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
            gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
            gl.depthMask(false);
            for (let index = 0; index < textPositions.length; index += 3) {
                let textWorldMatrix // = Matrix4.translation(textPositions[index], textPositions[index + 1], textPositions[index + 2]);
                
                // 由于 pos 在视图空间，表示它是一个从眼睛位置出发的一个向量
                // 所以沿着向量朝眼睛方向移动一定距离
                var fromEye = Matrix4.normalize([cameraPosition[0], cameraPosition[1], cameraPosition[2]]);
                var amountToMoveTowardEye = 150;  // 因为 F 是 150 个单位长
                var viewX = textPositions[index] + fromEye[0] * amountToMoveTowardEye;
                var viewY = textPositions[index + 1] + fromEye[1] * amountToMoveTowardEye;
                var viewZ = textPositions[index + 2] + fromEye[2] * amountToMoveTowardEye;
                //var desiredTextScale = -1 / gl.canvas.height;  // 1x1 像素大小
                //var scale = viewZ * desiredTextScale;
                
                let rm = Matrix4.copy(mat);
                rm[12] = rm[13] = rm[14] = 0;
                textWorldMatrix = Matrix4.translation(viewX, viewY, viewZ);
                textWorldMatrix = Matrix4.multiply(textWorldMatrix, rm);
                textWorldMatrix = Matrix4.multiply(textWorldMatrix, Matrix4.scaling(textWidth / 2, textHeight / 2, 1));

                let tviewProjectionMatrix = Matrix4.multiply(projectionMatrix, viewMatrix);
                tviewProjectionMatrix = Matrix4.multiply(tviewProjectionMatrix, textWorldMatrix);

                textUniforms.u_matrix = tviewProjectionMatrix;
                textUniforms.u_texture = textTexture;

                // gl.useProgram(this.textProgramInfo.program);
                // WebGLUtil.setBuffersAndAttributes(gl,this.textProgramInfo.attribSetters,textBufferInfo);
                // WebGLUtil.setUniforms(this.textProgramInfo.uniformSetters,textUniforms);
                // WebGLUtil.drawBufferInfo(gl,textBufferInfo);

                gl.useProgram(this.textProgramInfo.program);
                WebGLUtil.setBuffersAndAttributes(gl, this.textProgramInfo.attribSetters, rectTextBufferInfo);
                WebGLUtil.setUniforms(this.textProgramInfo.uniformSetters, textUniforms);
                WebGLUtil.drawBufferInfo(gl, rectTextBufferInfo);
            }


        }
        this.draw = drawScene;
    }

    // public override draw(param?: any): void {
    //     const gl = Render.GL;

    // }
}